import React, { useState, useRef } from 'react'
import { lazy } from 'ice'
import useRxdb from '@/components/Rxdb'
import '@/components/Notification'
import { handleData, getUGM } from '@/utils/handlePrimitive'
import { RGStretching, RGStretchingTouch } from '@/utils/RGStretching'
import { translate, isInPolygon } from '@/utils/tools'
import { v4 as uuidv4 } from 'uuid'
import { Icon } from '@alifd/next'
import useHistory from '@/components/HistoryTravel'
import store from '@/store'
import { useMemoizedFn, useThrottleFn, useCreation } from 'ahooks'
import { cloneDeep, isUndefined } from 'lodash-es'
import styles from './index.module.scss'

const Viewer = lazy(() => import('@/components/Viewer'))
const Entity = lazy(() => import('@/components/Entity'))
const BIM = lazy(() => import('@/components/BIM'))
const Project = lazy(() => import('@/components/Project'))

const create_point = (x, y) => {
  const newPId = uuidv4()
  const newPoint = {
    definition: 'point',
    id: newPId,
    location: [x, y, 0],
    name: newPId,
    value: newPId
  }
  return newPoint
}

const door_map = {}
const door_normal = {}
const doors_in_room = {}
const room_to_rooms = {}
let rooms_in_apartment = []
let num = 0

const get_2points_by_door = (line, data, s = 0.5) => {
  // 得到一条线的1/4、3/4处垂线上4个点
  const sp = data.docs[line[0]]
  const ep = data.docs[line[1]]
  const [spx, spy] = sp.location
  const [epx, epy] = ep.location
  const zx = (spx + epx) * 0.5    // 中点
  const zy = (spy + spy) * 0.5
  const dy = (epy - spy) * s      // 
  const dx = (epx - spx) * s
  const p1 = [zx - dy - dx * 0.25, zy + dx - dy * 0.25]
  const p2 = [zx + dy - dx * 0.25, zy - dx - dy * 0.25]
  const p3 = [zx - dy + dx * 0.25, zy + dx + dy * 0.25]
  const p4 = [zx + dy + dx * 0.25, zy - dx + dy * 0.25]
  return [p1, p2, p3, p4]
}

const get_room_by_point = (point, bim) => {
  // 通过点在房间内，返回对应房间
  for (let i = 0; i < bim.cols.room.length; i++) {
    const r = bim.cols.room[i]
    // console.log(r.name)
    if (isInPolygon(point, r.points)) return r
  }
  // bim.cols.room.forEach(r => {
  //     if (isInPolygon(point, r.points)) return r
  // })
}

const get_room_relation = (bim, data) => {
  // 得到房间相连的其他房间关系
  // console.log(door_map)
  rooms_in_apartment = bim.cols.room.filter(room => room.apartment && bim.docs[room.apartment] && bim.docs[room.apartment].name.indexOf('公区') > -1).map(o => o.id)
  for (const i in door_map) {
    const j_door = bim.docs[door_map[i]]
    const i_door = bim.docs[i]
    const j_room = bim.docs[j_door.room]
    if (!room_to_rooms[i_door.room]) room_to_rooms[i_door.room] = []
    if (room_to_rooms[i_door.room].indexOf(j_room) === -1 && rooms_in_apartment.indexOf(j_room.id) === -1) room_to_rooms[i_door.room].push(j_room)
  }
  const doorLayerId = data.cols.layer.find(i => i.type === 'Door').id
  const windowLayerId = data.cols.layer.find(i => i.type === 'Window').id
  const dwLines = data.cols.line.filter(i => i.layer === doorLayerId || i.layer === windowLayerId)
  for (const i in dwLines) {
    const line = dwLines[i]
    // console.log(line)
    const [p1, p2, , ] = get_2points_by_door([line.start, line.end], data, 0.1)
    const r1 = get_room_by_point(p1, bim)
    const r2 = get_room_by_point(p2, bim)
    if (r1 && r2) {
      if (!room_to_rooms[r1.id]) room_to_rooms[r1.id] = []
      if (room_to_rooms[r1.id].indexOf(r2) === -1 && rooms_in_apartment.indexOf(r2.id) === -1) room_to_rooms[r1.id].push(r2)
      if (!room_to_rooms[r2.id]) room_to_rooms[r2.id] = []
      if (room_to_rooms[r2.id].indexOf(r1) === -1 && rooms_in_apartment.indexOf(r1.id) === -1) room_to_rooms[r2.id].push(r1)
    } else {
      const [p3, p4, , ] = get_2points_by_door([line.start, line.end], data, 0.4)
      const r3 = get_room_by_point(p3, bim)
      const r4 = get_room_by_point(p4, bim)
      if (r3 && r4) {
        if (!room_to_rooms[r3.id]) room_to_rooms[r3.id] = []
        if (room_to_rooms[r3.id].indexOf(r4) === -1 && rooms_in_apartment.indexOf(r4.id) === -1) room_to_rooms[r3.id].push(r4)
        if (!room_to_rooms[r4.id]) room_to_rooms[r4.id] = []
        if (room_to_rooms[r4.id].indexOf(r3) === -1 && rooms_in_apartment.indexOf(r3.id) === -1) room_to_rooms[r4.id].push(r3)
      }
    }
  }
}

const is_entry_door = (door, bim, data) => {
  // 判断是否是入户门
  const [p1, p2, p3, p4] = get_2points_by_door(door.lines[0], data)
  let flag = false
  bim.cols.room.forEach(a_room => {
    if (a_room.apartment && bim.docs[a_room.apartment] && bim.docs[a_room.apartment].name.indexOf('公区') > -1) {
      if ((isInPolygon(p1, a_room.points) ^ isInPolygon(p3, a_room.points))) {
        const r2 = get_room_by_point(p2, bim)
        // console.log([door.name, r2, a_room, p1, p2, r2 && !r2.apartment])
        if (r2 && (!r2.apartment || (r2.apartment && !bim.docs[r2.apartment]) || (r2.apartment && bim.docs[r2.apartment] && bim.docs[r2.apartment].name.indexOf('公区') === -1))) {
          flag = r2
        }
      } else if ((isInPolygon(p2, a_room.points) ^ isInPolygon(p4, a_room.points))) {
        const r2 = get_room_by_point(p1, bim)
        // console.log([door.name, r2, a_room, p1, p2, r2 && !r2.apartment])
        if (r2 && (!r2.apartment || (r2.apartment && !bim.docs[r2.apartment]) || (r2.apartment && bim.docs[r2.apartment] && bim.docs[r2.apartment].name.indexOf('公区') === -1))) {
          flag = r2
        }
      }
    }
  })
  return flag
}

const get_door_map = (doors, data) => {
  // 得到门与门对应关系
  // const door_map = {}
  for (let i = 0; i < doors.length; i++) {
    const i_door = doors[i]
    const [i_s_id, i_e_id] = i_door.lines[0]
    const i_s = data.docs[i_s_id]
    const i_e = data.docs[i_e_id]
    // if (i_door.name === '门0138') console.log([i_door.room, door_map[i_door.id], doors_in_room[i_door.room]])
    if (!doors_in_room[i_door.room]) doors_in_room[i_door.room] = []
    if (doors_in_room[i_door.room].indexOf(i_door) === -1) doors_in_room[i_door.room].push(i_door)
    if (door_map[i_door.id]) continue
    const i_len = parseInt(((i_s.location[0] - i_e.location[0]) ** 2 + (i_s.location[1] - i_e.location[1]) ** 2) ** 0.5)
    for (let j = i + 1; j < doors.length; j++) {
      const j_door = doors[j]
      if (!door_map[i_door.id] && !door_map[j_door.id]) {
        const [j_s_id, j_e_id] = j_door.lines[0]
        const j_s = data.docs[j_s_id]
        const j_e = data.docs[j_e_id]
        const j_len = parseInt(((j_s.location[0] - j_e.location[0]) ** 2 + (j_s.location[1] - j_e.location[1]) ** 2) ** 0.5)
        const z_1 = ((i_s.location[0] - j_e.location[0]) ** 2 + (i_s.location[1] - j_e.location[1]) ** 2) ** 0.5
        const z_2 = ((j_s.location[0] - i_e.location[0]) ** 2 + (j_s.location[1] - i_e.location[1]) ** 2) ** 0.5
        const z_3 = ((j_s.location[0] - i_s.location[0]) ** 2 + (j_s.location[1] - i_s.location[1]) ** 2) ** 0.5
        console.log(j_door.name, i_door.name, i_len - j_len, parseInt(z_1) === parseInt(z_2), Math.min(z_1, z_3) < i_len / 3)
        if (Math.abs(i_len - j_len) <= 1 && Math.abs(parseInt(z_1) - parseInt(z_2)) <= 1 && Math.min(z_1, z_3) < i_len / 3) {
          door_map[i_door.id] = j_door.id
          door_map[j_door.id] = i_door.id
          // console.log(j_door.name, i_door.name)
          if (Math.min(z_1, z_3) === z_1) {
            const nx = (j_e.location[0] - i_s.location[0]) / z_1
            const ny = (j_e.location[1] - i_s.location[1]) / z_1
            door_normal[i_door.id] = [nx, ny]
            door_normal[j_door.id] = [-nx, -ny]
          } else {
            const nx = (j_s.location[0] - i_s.location[0]) / z_3
            const ny = (j_s.location[1] - i_s.location[1]) / z_3
            door_normal[i_door.id] = [nx, ny]
            door_normal[j_door.id] = [-nx, -ny]
          }
        }
      }
    }
  }
  return door_map
}

// const get_roomIds_by_entry_door = (i_door, roomIds, bim) => {
//   if (!door_map[i_door.id]) return roomIds
//   const j_door = bim.docs[door_map[i_door.id]]
//   const j_room = bim.docs[j_door.room]
//   // console.log([i_door.name, j_door.name, j_room.name])
//   if (roomIds.indexOf(j_room.id) > -1) return roomIds
//   roomIds.push(j_room.id)
//   const doors = doors_in_room[j_door.room]
//   // console.log(doors)
//   if (!doors) return roomIds
//   for (let k = 0; k < doors.length; k++) {
//     const k_door = {...doors[k]}
//     const k_room = bim.docs[k_door.room]
//     // if (k_door.id === j_door.id || k_room.apartment) continue
//     if (k_door.id === j_door.id || (k_room.apartment && bim.docs[k_room.apartment] && bim.docs[k_room.apartment].name.indexOf('公区') > -1)) continue
//     get_roomIds_by_entry_door(k_door, roomIds, bim)
//   }
//   return roomIds
// }

const get_roomIds_by_entry_room = (i_room, roomIds, bim) => {
  if (rooms_in_apartment.indexOf(i_room.id) > -1 || (i_room.apartment && bim.docs[i_room.apartment] && bim.docs[i_room.apartment].name.indexOf('公区') > -1)) return roomIds
  roomIds.push(i_room.id)
  rooms_in_apartment.push(i_room.id)
  const rooms = room_to_rooms[i_room.id]
  if (!rooms) return roomIds
  for (let k = 0; k < rooms.length; k++) {
    const k_room = rooms[k]
    // if (k_room.apartment) continue
    if (k_room.apartment && bim.docs[k_room.apartment] && bim.docs[k_room.apartment].name.indexOf('公区') > -1) continue
    get_roomIds_by_entry_room(k_room, roomIds, bim)
  }
  return roomIds
}

const create_apartment_by_entry_door = (j_room, bim) => {
  const bimId = bim.cols.bim[0].id
  const roomIds = []
  const roomNames = {}
  // get_roomIds_by_entry_door(i_door, roomIds, bim)
  get_roomIds_by_entry_room(j_room, roomIds, bim)
  // console.log(roomIds.length)
  if (roomIds.length === 0) {
    // console.log(roomIds)
    return {addData: [], updateData: [], deleteData: []}
  }
  const apartment = {
    name: `${translate('apartment')}0${num + 1}`,
    id: uuidv4(),
    bim: bimId,
    definition: 'apartment'
  }
  num += 1
  const docs = roomIds.map(roomId => {
    const room = bim.docs[roomId]
    const roomName = room.name
    if (isUndefined(roomNames.roomName)) {
      roomNames[roomName] = 1
    } else {
      roomNames[roomName] += 1
    }
    return { ...room, name: `${roomName}${roomNames[roomName]}`, apartment: apartment.id }
  })
  return {addData: [apartment], updateData: docs, deleteData: []}
}

const filter_entry_door = (bim, data) => {
  const doors = bim.cols.door
  const door_map = get_door_map(doors, data)
  get_room_relation(bim, data)
  console.log(room_to_rooms)
  let addData = []
  let updateData = []
  for (let i = 0; i < doors.length; i++) {
    const i_door = {...doors[i]}
    if (!door_map[i_door.id]) {
      const flag = is_entry_door(i_door, bim, data)
      // console.log(flag)
      if (flag) door_map[i_door.id] = i_door.id
      else continue
      // console.log(i_door.name)
    }
    const j_door = bim.docs[door_map[i_door.id]]
    // console.log([i_door.name, j_door.name])
    // const j_door = doors.filter(d => d.id === door_map[i_door.id])[0]
    const i_room = bim.docs[i_door.room]
    let j_room = bim.docs[j_door.room]
    if (i_room && j_room) {
      const i_apartment = bim.docs[i_room.apartment]
      const j_apartment = bim.docs[j_room.apartment]
      // if (i_apartment && j_apartment && (((i_apartment.name + j_apartment.name).split('公区')).length - 1 === 1) && j_apartment.name.indexOf('公区') === -1) {
      if ((i_apartment && i_apartment.name.indexOf('公区') > -1 && ((j_apartment && j_apartment.name.indexOf('公区') === -1) || !j_apartment)) || is_entry_door(i_door, bim, data)) {
        // if (((i_apartment && i_apartment.name.indexOf('公区') > -1) || is_entry_door(i_door, bim, data)) && ((j_apartment && j_apartment.name.indexOf('公区') === -1 && rooms_in_apartment.indexOf(j_room.id) === -1) || !j_apartment)) {
        if (is_entry_door(i_door, bim, data)) j_room = is_entry_door(i_door, bim, data)
        i_door.entry = true
        i_door.normal = door_normal[i_door.id]
        const res = create_apartment_by_entry_door(j_room, bim)
        addData = [...addData, ...res.addData]
        updateData = [...updateData, ...res.updateData]
      } else {
        i_door.entry = false
      }
      updateData.push(i_door)
    }
  }
  return  {addData, updateData}
}

const Plan = () => {
  const [graphState, graphDispatchers] = store.useModel('graph')
  const { data, bim, selectedStoreyIds, selectedIds, projectData, projectId, stage, ugmId } = graphState

  // const [leftW, setLeftW] = useState('calc(15% - 12px)')
  // const [middleW, setMiddleW] = useState('calc(70% - 0px)')
  // const [rightW, setRightW] = useState('calc(15% - 12.5px)')
  // const [upH, setUpH] = useState('calc(70%)')
  // const [downH, setDownH] = useState('calc(30% - 12px)')
  const [box, setBox] = useState({
    leftW: 'calc(15% - 12px)',
    middleW: 'calc(70% - 0px)',
    rightW: 'calc(15% - 12.5px)',
    upH: 'calc(70%)',
    downH: 'calc(30% - 12px)'
  })
  const [splitScreenState, setSplitScreenState] = useState(false)

  const entityTreeRef = useRef()
  const BIMTreeRef = useRef()
  const viewerRef = useRef()
  const Background = useRef()
  const Main = useRef()
  const Left = useRef()
  const Middle = useRef()
  const Right = useRef()
  const Up = useRef()
  const Down = useRef()

  const rxdb = useRxdb()
  const history = useHistory()

  const { back, forward } = history

  const setEye = useMemoizedFn(arg => {
    const { ids: entityTreeIds, keys: entityTreeKeys } = entityTreeRef.current.setEye(arg)
    const { ids: BIMTreeIds, keys: BIMTreeKeys } = BIMTreeRef.current.setEye(arg)
    graphDispatchers.update({
      [arg.type]: {
        ids: [...entityTreeIds, ...BIMTreeIds],
        keys: { ...entityTreeKeys, ...BIMTreeKeys }
      }
    })
  })

  const getSelectionCells = useMemoizedFn(arg => viewerRef.current.getSelectionCells(arg))

  const getOpenings = useMemoizedFn(arg => viewerRef.current.getOpenings(arg))

  const addBIM = useMemoizedFn(({ name, type, fatherId }) => {
    const selectionCells = getSelectionCells()
    const ids = selectionCells.map(i => i.id)
    const fatherType = bim && bim.docs && bim.docs[fatherId] && bim.docs[fatherId].definition
    switch (type) {
      case 'building':
        const installment = projectData.docs[fatherId]
        const buildingLength = projectData.cols.building.filter(i => i.installment === installment.id).length
        const newBuilding = {
          id: uuidv4(),
          name: `${translate('building')}0${buildingLength + 1}`,
          installment: installment.id,
          definition: 'building'
        }
        graphDispatchers.update({
          projectData: {
            cols: { ...projectData.cols, building: [...projectData.cols.building, newBuilding] },
            docs: { ...projectData.docs, [newBuilding.id]: newBuilding }
          }
        })
        break
      case 'storey':
        const building = projectData.docs[fatherId]
        const storeyLength = projectData.cols.storey.filter(i => i.building === building.id).length
        const newStorey = {
          id: uuidv4(),
          name: `${translate('storey')}0${storeyLength + 1}`,
          building: building.id,
          ugm: '',
          definition: 'storey'
        }
        graphDispatchers.update({
          projectData: {
            cols: { ...projectData.cols, storey: [...projectData.cols.storey, newStorey] },
            docs: { ...projectData.docs, [newStorey.id]: newStorey }
          }
        })
        break
      case 'apartment':
        const newTemplate = {
          name: name || `${translate('apartment')}0${bim.cols.apartment.length + 1}`,
          id: uuidv4(),
          bim: fatherId,
          definition: 'apartment'
        }
        rxdb.addDocs([newTemplate])
        break
      case 'separator':
        const newDocs = []
        const updateDocs = []
        const deleteDocs = []
        const separatorIds = selectedIds.filter(id => bim.cols.separator.findIndex(o => o.id === id) > -1)
        separatorIds.forEach((separatorId) => {
          const separator = bim.docs[separatorId]
          const separatorAsDoor = !separator.asDoor
          let separatorDoor = null
          const a_line = separator.line
          if (separatorAsDoor) {
            const newPoints = []
            const newDoors = []
            const newLines = []
            const startP = create_point(a_line[0], a_line[1], data)
            const startPId = startP.id
            newPoints.push(startP)
            const endP = create_point(a_line[2], a_line[3], data)
            const endPId = endP.id
            newPoints.push(endP)
            const newLineId = uuidv4()
            const lineLayerId = data.cols.layer.find(i => i.type === 'Door').id
            const nLine = {
              material: data.cols.line[0].material,
              id: newLineId,
              layer: lineLayerId,
              definition: 'line',
              start: startPId,
              end: endPId,
              name: newLineId,
              value: newLineId
            }
            newLines.push(nLine)
            const newDoorId = uuidv4()
            const newDoor = {
              data: [],
              lines: [startPId, endPId],
              name: name || `${translate('door')}0${bim.cols.door.length + 1}`,
              room: separator.room,
              id: newDoorId,
              definition: 'door'
            }
            newDoors.push(newDoor)
            newDocs.push(startP)
            newDocs.push(endP)
            newDocs.push(nLine)
            separatorDoor = newLineId
          }
          else {
            deleteDocs.push(separator.door)
            separatorDoor = null
          }
          console.log(separator)
          const newSeparator = {...separator}
          newSeparator.asDoor = separatorAsDoor
          newSeparator.door = separatorDoor
          updateDocs.push(newSeparator)
        })
        console.log(updateDocs)
        const timestamp = { id: data.cols.timestamp.find(i => i.definition === 'timestamp').id, timestamp: Date.now().toString(), definition: 'timestamp' }
        updateDocs.push(timestamp)
        // rxdb.addDocs(newDocs)
        // rxdb.updateDocs(updateDocs)
        rxdb.changeDocs({addData: newDocs, updateData: updateDocs, deleteData: deleteDocs})
        break
      case 'door':
        const newDoor = {
          data: ids,
          lines: [],
          name: name || `${translate('door')}0${bim.cols.door.length + 1}`,
          room: fatherId,
          id: uuidv4(),
          definition: 'door'
        }
        selectionCells.forEach(cell => {
          if (cell.startPId && cell.endPId) newDoor.lines.push([cell.startPId, cell.endPId])
        })
        rxdb.addDocs([newDoor])
        break
      case 'window':
        const newWindow = {
          data: ids,
          lines: [],
          name: name || `${translate('window')}0${bim.cols.window.length + 1}`,
          room: fatherId,
          id: uuidv4(),
          definition: 'window'
        }
        selectionCells.forEach(cell => {
          if (cell.startPId && cell.endPId) newWindow.lines.push([cell.startPId, cell.endPId])
        })
        rxdb.addDocs([newWindow])
        break
      case 'drywall':
      case 'mainwall':
        const mainwallLayer = data.cols.layer.find(i => i.type === 'MainWall')
        const mainwallLayerId = mainwallLayer ? mainwallLayer.id : null
        const drywallLayer = data.cols.layer.find(i => i.type === 'DryWall')
        const drywallLayerId = drywallLayer ? drywallLayer.id : null
        const mainwallLineIds = ids.filter(
          id => data.docs[id].definition === 'line' && data.docs[id].layer === mainwallLayerId
        )
        const drywallLineIds = ids.filter(
          id => data.docs[id].definition === 'line' && data.docs[id].layer === drywallLayerId
        )
        const MainWallsNumber = bim.cols.mainwall.length
        const DryWallsNumber = bim.cols.drywall.length
        const newMainWalls = mainwallLineIds.map((lineId, index) => {
          const line = data.docs[lineId]
          const newMainWall = {
            data: [line.id],
            lines: [[line.start, line.end]],
            name: `${translate('MainWall')}0${MainWallsNumber + index + 1}`,
            room: fatherId,
            original: line.original,
            id: uuidv4(),
            definition: 'mainwall'
          }
          return newMainWall
        })
        const newDryWalls = drywallLineIds.map((lineId, index) => {
          const line = data.docs[lineId]
          const newDryWall = {
            data: [line.id],
            lines: [[line.start, line.end]],
            name: `${translate('DryWall')}0${DryWallsNumber + index + 1}`,
            room: fatherId,
            original: line.original,
            id: uuidv4(),
            definition: 'drywall'
          }
          return newDryWall
        })
        rxdb.addDocs([...newDryWalls, ...newMainWalls])
        break
      case 'beam':
        const newBeam = {
          data: ids,
          lines: [],
          name: name || `${translate('beam')}0${bim.cols.beam.length + 1}`,
          room: fatherId,
          id: uuidv4(),
          definition: 'beam'
        }
        selectionCells.forEach(cell => {
          if (cell.startPId && cell.endPId) newBeam.lines.push([cell.startPId, cell.endPId])
        })
        rxdb.addDocs([newBeam])
        break
      case 'column':
        const newColumn = {
          data: ids,
          lines: [],
          name: name || `${translate('column')}0${bim.cols.column.length + 1}`,
          room: fatherId,
          id: uuidv4(),
          definition: 'column'
        }
        selectionCells.forEach(cell => {
          if (cell.startPId && cell.endPId) newColumn.lines.push([cell.startPId, cell.endPId])
        })
        rxdb.addDocs([newColumn])
        break
      case 'opening':
        const openings = getOpenings(selectionCells)
        const newOpenings = []
        openings.forEach((opening, index) => {
          newOpenings.push({
            data: [opening[0], opening[1]],
            room: fatherId,
            id: opening[2],
            name: `${translate('opening')}0${index + 1}`,
            definition: 'opening'
          })
        })
        rxdb.addDocs(newOpenings)
        break
      case 'room':
        if (fatherType === 'bim') {
          const newRoom = {
            name: name || `${translate('room')}0${bim.cols.room.length + 1}`,
            apartment: fatherType === 'apartment' ? fatherId : undefined,
            bim: fatherType === 'bim' ? fatherId : undefined,
            id: uuidv4(),
            definition: 'room'
          }
          rxdb.addDocs([newRoom])
        } else if (fatherType === 'apartment') {
          const apartment = bim.docs[fatherId]
          let scanstationIds = []
          const roomNames = {}
          const roomIds = selectedIds.filter(id => bim.cols.room.findIndex(o => o.id === id) > -1)
          if (apartment.name && apartment.name.indexOf('公区') > -1) {
            scanstationIds = bim.cols.scanstation.filter(scan => roomIds.indexOf(scan.room) > -1).map(o => o.id)
          }
          const docs = roomIds.map(roomId => {
            const room = bim.docs[roomId]
            const roomName = room.name
            if (isUndefined(roomNames.roomName)) {
              roomNames[roomName] = 1
            } else {
              roomNames[roomName] += 1
            }
            return { ...room, name: `${roomName}${roomNames[roomName]}`, apartment: fatherId }
          })
          const res = filter_entry_door(bim, data)
          rxdb.changeDocs({addData: res.addData, updateData: [...docs, ...res.updateData], deleteData: scanstationIds})
        }
        break
      default:
        break
    }
  })

  const updateBIM = useMemoizedFn(data => {
    const id = data.id
    if (bim && bim.docs && bim.docs[data.id]) {
      const newScanstation = []
      const roomScanstation = {}
      bim.cols.room.forEach(i => {
        roomScanstation[i.id] = 0
      })
      bim.cols.scanstation.forEach(i => {
        const room = bim.cols.room.find(o => isInPolygon(i.point, o.points))
        if (room) {
          const apartment = bim.docs[room.apartment]
          if (apartment.id === id) {
            roomScanstation[room.id] += 1
            const scanstationName = `${data.num}-${room.name}-${roomScanstation[room.id]}`
            newScanstation.push({ ...i, name: scanstationName })
          } else if (!isUndefined(apartment.num)) {
            roomScanstation[room.id] += 1
            const scanstationName = `${apartment.num}-${room.name}-${roomScanstation[room.id]}`
            newScanstation.push({ ...i, name: scanstationName })
          }
        }
      })
      rxdb.updateDocs([...newScanstation, { ...bim.docs[id], ...data }])
    }
  })

  const updateBIMName = useMemoizedFn(({ value, id }) => {
    if (bim && bim.docs && bim.docs[id]) {
      console.log(value)
      let scanstationIds = []
      let res = {addData: [], updateData: []}
      const roomIds = bim.cols.room.filter(room => room.apartment === id).map(o => o.id)
      if (value && value.indexOf('公区') > -1) {
        scanstationIds = bim.cols.scanstation.filter(scan => roomIds.indexOf(scan.room) > -1).map(o => o.id)
        res = filter_entry_door(bim, data)
      }
      console.log({addData: res.addData, updateData: [{ ...bim.docs[id], name: value }, ...res.updateData], deleteData: scanstationIds})
      rxdb.changeDocs({addData: res.addData, updateData: [{ ...bim.docs[id], name: value }, ...res.updateData], deleteData: scanstationIds})
    } else if (projectData.docs[id]) {
      const newDocs = { ...projectData.docs, [id]: { ...projectData.docs[id], name: value } }
      const newCols = {
        building: [],
        installment: [],
        project: [],
        storey: [],
        ugm: []
      }
      for (const key in newDocs) {
        const node = newDocs[key]
        const definition = node.definition
        if (definition) {
          if (!newCols[definition]) newCols[definition] = []
          newCols[definition].push(node)
        }
      }
      graphDispatchers.update({ projectData: { cols: newCols, docs: newDocs } })
    }
  })

  const updateApartmentName = useMemoizedFn(() => {
    const apartment = bim.cols.apartment
    function sum(arr) {
      let s = 0
      arr.forEach(val => {
        s += val
      }, 0)
      return s
    }
    const getCenterX = apartmentId => {
      const rooms = bim.cols.room.filter(i => i.apartment === apartmentId)
      const allX = []
      rooms.forEach(i => {
        if (i.points) {
          i.points.forEach(o => allX.push(o[0]))
        }
      })
      return sum(allX) / allX.length
    }

    const apartmentIds = apartment.map(i => i.id)
    const centerXArr = apartmentIds.map(i => getCenterX(i))
    const obj = {}
    centerXArr.forEach((i, index) => {
      obj[i.toString()] = apartmentIds[index]
    })
    function compare(val1, val2) {
      return val2 - val1
    }
    centerXArr.sort(compare)
    const newApartments = []
    centerXArr.forEach((i, index) => {
      const apartmentId = obj[i.toString()]
      newApartments.push({ ...bim.docs[apartmentId], name: `户型0${index + 1}` })
    })
    rxdb.updateDocs(newApartments)
  })

  const deleteBIMs = useMemoizedFn(({ ids, type, fatherId }) => {
    const fatherType = bim && bim.docs && bim.docs[fatherId] && bim.docs[fatherId].definition
    if (type === 'room' && fatherType === 'apartment') {
      const roomIds = ids
      const docs = roomIds.map(roomId => {
        const room = bim.docs[roomId]
        return { ...room, apartment: null }
      })
      rxdb.updateDocs(docs)
    } else {
      if (type === 'room') {
        const roomIds = ids
        const scanstationIds = bim.cols.scanstation.filter(i => i.room && roomIds.includes(i.room)).map(i => i.id)
        const drywallIds = bim.cols.drywall.filter(i => i.room && roomIds.includes(i.room)).map(i => i.id)
        const mainwallIds = bim.cols.mainwall.filter(i => i.room && roomIds.includes(i.room)).map(i => i.id)
        const doorIds = bim.cols.door.filter(i => i.room && roomIds.includes(i.room)).map(i => i.id)
        const windowIds = bim.cols.window.filter(i => i.room && roomIds.includes(i.room)).map(i => i.id)
        rxdb.deleteDocs([...roomIds, ...scanstationIds, ...drywallIds, ...mainwallIds, ...doorIds, ...windowIds])
      } else if (type === 'building' || type === 'storey') {
        const newDocs = { ...projectData.docs }
        const newCols = {
          building: [],
          installment: [],
          project: [],
          storey: [],
          ugm: []
        }
        ids.forEach(id => delete newDocs[id])
        for (const key in newDocs) {
          const node = newDocs[key]
          const definition = node.definition
          if (definition) {
            if (!newCols[definition]) newCols[definition] = []
            newCols[definition].push(node)
          }
        }
        graphDispatchers.update({ projectData: { cols: newCols, docs: newDocs } })
      } else if (type === 'apartment' && ids.length === 0) {
        const apartments = {}
        bim.cols.apartment.forEach(i => {
          apartments[i.id] = bim.cols.room.filter(o => o.apartment === i.id).map(p => p.id)
        })
        const selectRoomIds = selectedIds.filter(id => bim.docs[id] && bim.docs[id].definition === 'room')
        const apartmentId2del = []
        for (const id in apartments) {
          if (apartments[id].length > 0 && apartments[id].every(o => selectRoomIds.includes(o))) {
            apartmentId2del.push(id)
          }
        }
        rxdb.deleteDocs(apartmentId2del)
      } else if (type === 'separator') {
        const doorIds = []
        ids.forEach((id) => {
          const separator = bim.docs[id]
          doorIds.push(id)
          doorIds.push(separator.door)
          // return separator.door
        })
        console.log(['删除', doorIds])
        rxdb.deleteDocs(doorIds)
      } else {
        rxdb.deleteDocs(ids)
      }
    }
  })

  const autoplan = useMemoizedFn(async ({ cb, mergeList, stage: _stage, type }) => {
    if (!_stage) _stage = stage
    cb(true)
    const res = await graphDispatchers.divideRoom({ stage: _stage, mergeList, type })
    cb(false)
    rxdb.addData(handleData(res))
  })

  const manualplan = useMemoizedFn(async ({ points = [[14320, 29938]], cb, type }) => {
    cb(true)
    const res = await graphDispatchers.planningScanstation({ points, stage: stage, type })
    cb(false)
    rxdb.addData(handleData(res))
  })

  const onMousedown = (e, type, box, box2, setBox, setBox2) => RGStretching(e, type, box, box2, setBox, setBox2)

  const onTouchStart = (e, type, box, box2, setBox, setBox2) => RGStretchingTouch(e, type, box, box2, setBox, setBox2)

  const removeDb = useMemoizedFn(() => rxdb.removeDb())

  const getDataByUploadButton = useMemoizedFn(({ architecture, structure, ugm }) => {
    const data = handleData({ architecture, structure, ugm })
    rxdb.addData(data)
    ugm = getUGM({ data })
    if (ugm) graphDispatchers.saveData({ data: ugm, type: 'ugm' })
  })

  window.data = data
  window.bim = bim
  window.projectData = projectData
  window.selectedIds = selectedIds

  window.getUGM = useMemoizedFn(() => getUGM({ data: data, bim: bim }))

  window.getProjectData = useMemoizedFn(() => {
    const newUGM = {
      id: ugmId,
      name: ugmId,
      url: `ugmJson/${ugmId}.json`,
      definition: 'ugm',
      project: projectId
    }
    const newCols = cloneDeep(projectData.cols)
    newCols.storey.forEach((i, len) => {
      if (selectedStoreyIds.includes(i.id)) {
        newCols.storey[len].ugm = newUGM.id
      }
    })
    newCols.storey = newCols.storey.filter(i => i.ugm)
    let sign = false
    newCols.ugm.forEach((i, len) => {
      if (i.id === newUGM.id) {
        sign = true
        newCols.ugm[len] = newUGM
      }
    })
    if (!sign) newCols.ugm.push(newUGM)
    return newCols
  })

  window.refreshProjectData = useMemoizedFn(async () => await graphDispatchers.getProject())

  window.getTaskIds = useMemoizedFn(() => {
    const res = []
    projectData.cols.storey
      .filter(i => selectedStoreyIds.includes(i.id))
      .forEach(i => {
        res.push({
          taskId: i.ugm,
          storeyId: projectData.docs[i.id].recent_id,
          buildingId: projectData.docs[i.building].recent_id,
          storeyName: projectData.docs[i.id].name,
          buildingName: projectData.docs[i.building].name
        })
      })
    return res
  })

  const createViewer = useMemoizedFn(() => {
    return (
      <Viewer
        ref={viewerRef}
        getDataByUploadButton={getDataByUploadButton}
        autoplan={autoplan}
        manualplan={manualplan}
        setEye={setEye}
        back={back}
        forward={forward}
        deleteBIMs={deleteBIMs}
        removeDb={removeDb}
        updateApartmentName={updateApartmentName}
        setSplitScreenState={() => setSplitScreenState(!splitScreenState)}
        updateBIM={updateBIM}
        scanstationCheck={scanstationCheck}
        splitScreenState={splitScreenState}
        box={box}
      />
    )
  })

  const scanstationCheck = useMemoizedFn(() => {
    const newBIM = cloneDeep(bim)
    const scanstationIdsToDelete = []
    newBIM.cols.scanstation.forEach(i => {
      let { mainwalls, drywalls } = i
      if (!mainwalls) mainwalls = []
      if (!drywalls) drywalls = []
      const allWallsLength = mainwalls.length + drywalls.length
      if (allWallsLength < 3) {
        scanstationIdsToDelete.push(i.id)
      }
    })
    if (scanstationIdsToDelete.length > 0) {
      window.openNotification({ type: 'warning', title: '检查到错误站点' })
      rxdb.deleteDocs(scanstationIdsToDelete)
    } else {
      window.openNotification({ type: 'success', title: '所有站点正常' })
    }
  })

  const { run: setUHDHThrottle } = useThrottleFn((upH, downH) => setBox({ ...box, upH, downH }), { wait: 100 })
  const { run: setLWMWThrottle } = useThrottleFn((leftW, middleW) => setBox({ ...box, leftW, middleW }), {
    wait: 100
  })
  const { run: setMWRWThrottle } = useThrottleFn((middleW, rightW) => setBox({ ...box, middleW, rightW }), {
    wait: 100
  })

  const style1 = useCreation(() => ({ width: '100%', height: '100%' }), [])
  const style2 = useCreation(() => ({ width: 'calc(50% - 1px)', height: '100%', float: 'right' }), [])
  const style3 = useCreation(
    () => ({ width: !splitScreenState ? '100%' : 'calc(50% - 1px)', height: '100%', float: 'left' }),
    [splitScreenState]
  )
  const style4 = useCreation(() => ({ width: '100%', height: box.downH, float: 'inherit' }), [box])
  const style5 = useCreation(() => ({ width: box.leftW }), [box])
  const style6 = useCreation(() => ({ width: '100%', height: box.upH }), [box])
  const style7 = useCreation(() => ({ width: box.middleW }), [box])
  const style8 = useCreation(() => ({ width: box.rightW }), [box])

  return (
    <div ref={Background} className={styles.background}>
      <div ref={Main} className={styles.container}>
        <div ref={Left} className={styles.Left} style={style5}>
          <div ref={Up} className={styles.Up} style={style6}>
            <Project refresh={rxdb.refresh} addBIM={addBIM} updateBIMName={updateBIMName} deleteBIMs={deleteBIMs} />
          </div>
          <div
            className={styles.horizontalDrag}
            onMouseDown={e => onMousedown(e, 'topBottom', Up.current, Down.current, setUHDHThrottle)}
            onTouchStart={e => onTouchStart(e, 'topBottom', Up.current, Down.current, setUHDHThrottle)}
          >
            <Icon className={styles.horizontalImg} size={'small'} type="sorting" />
          </div>
          <div ref={Down} className={styles.Down} style={style4}>
            <Entity ref={entityTreeRef} />
          </div>
        </div>
        <div
          className={styles.LeftVerticalDrag}
          onMouseDown={e => onMousedown(e, 'leftRight', Left.current, Middle.current, setLWMWThrottle)}
          onTouchStart={e => onTouchStart(e, 'leftRight', Left.current, Middle.current, setLWMWThrottle)}
        >
          <Icon className={styles.img} size={'small'} type="switch" />
        </div>
        <div ref={Middle} className={styles.Middle} style={style7}>
          <div style={style1}>
            <div style={style3}>{createViewer()}</div>
            {splitScreenState ? <div style={style2}>{createViewer()}</div> : null}
          </div>
        </div>
        <div
          className={styles.RightVerticalDrag}
          onMouseDown={e => onMousedown(e, 'leftRight', Middle.current, Right.current, setMWRWThrottle)}
          onTouchStart={e => onTouchStart(e, 'leftRight', Middle.current, Right.current, setMWRWThrottle)}
        >
          <Icon className={styles.img} size={'small'} type="switch" />
        </div>
        <div ref={Right} className={styles.Right} style={style8}>
          <BIM ref={BIMTreeRef} addBIM={addBIM} updateBIMName={updateBIMName} deleteBIMs={deleteBIMs} />
        </div>
      </div>
    </div>
  )
}

export default Plan
